<?php

class PostalcodeKmlParser {
  private $postalcodes = array();
  private $in_placemark = false;
  private $in_polygon = false;
  private $in_outer_boundrary = false;
  private $in_linear_ring = false;
  private $reading = false;
  private $placemark_name = Null;
  private $placemark_data = Null;
  
  public function parse($data) {
    $parser = xml_parser_create();
    
    xml_set_element_handler($parser, array($this, 'start_element'), array($this, 'end_element'));
    xml_set_character_data_handler($parser, array($this, 'data_handler'));
    
    xml_parse($parser, $data, TRUE);
    
    //Send remaining postalcodes
    if(count($this->postalcodes)) {
      postalcodes_parser_callback('kml', 'add', $this->postalcodes);
    }
    
    xml_parser_free($parser);
    
    return true;
  }
  
  private function finish_placemark() {
    $this->placemark_name = trim($this->placemark_name);
    $this->placemark_data = trim($this->placemark_data);
    
    $matches = array();
    if (preg_match('/^(\d{3,4})\s*-?\s*(\d{3,4})?$/', $this->placemark_name, $matches)) {
      $data = array(intval($matches[1]));
      if(!isset($matches[2])) {
        $data[1] = $data[0];
      }
      else {
        $data[1] = intval($matches[2]);
      }
      $data[2] = $this->placemark_data;
      
      $this->postalcodes[] = $data;
    }
    
    if(count($this->postalcodes)>=20) {
      postalcodes_parser_callback('kml', 'add', $this->postalcodes);
      $this->postalcodes = array();
    }
  }
  
  public function start_element($parser, $name, $attribs) {
    switch ($name) {
      case 'PLACEMARK':
        $this->in_placemark = true;
      break;
      case 'NAME':
        if ($this->in_placemark) {
          $this->placemark_name = '';
          $this->reading = 'name';
        }
      break;
      case 'POLYGON':
        if ($this->in_placemark) {
          $this->in_polygon = true;
        }
      break;
      case 'OUTERBOUNDARYIS':
        if ($this->in_polygon) {
          $this->in_outer_boundrary = true;
        }
      break;
      case 'LINEARRING':
        if ($this->in_outer_boundrary) {
          $this->in_linear_ring = true;
        }
      break;
      case 'COORDINATES':
        if ($this->in_linear_ring) {
          $this->placemark_data = '';
          $this->reading = 'coordinates';
        }
      break;
    }
  }
  
  public function end_element($parser, $name) {
    switch ($name) {
      case 'PLACEMARK':
        $this->in_placemark = false;
        $this->finish_placemark();
      break;
      case 'POLYGON':
        $this->in_polygon = false;
      break;
      case 'OUTERBOUNDARYIS':
        $this->in_outer_boundrary = false;
      break;
      case 'LINEARRING':
        $this->in_linear_ring = false;
      break;
      case 'NAME':
        $this->reading = false;
      break;
      case 'COORDINATES':
        $this->reading = false;
      break;
    }
  }
  
  public function data_handler($parser, $data) {
    if(!$this->reading) {
      return;
    }
    
    switch ($this->reading) {
      case 'coordinates':
        $this->placemark_data .= $data;
        break;
      case 'name':
        $this->placemark_name .= $data;
        break;
    }
  }
}